package sharetime.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SuppressWarnings("unchecked")
public class FileUtils {
	private static Logger logger = LoggerFactory.getLogger(FileUtils.class);

	private static final int BUFFER_SIZE = 1024;

	public static void copyDirectory(File srcDir, File destDir)
			throws IOException {
		copyDirectory(srcDir, destDir, false);
	}

	public static void copyDirectory(File srcDir, File destDir,
			boolean overwrite) throws IOException {
		File files[] = srcDir.listFiles();
		if (!destDir.exists())
			destDir.mkdirs();
		else
			logger.debug(destDir.getAbsolutePath() + " already exists");
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				File file = files[i];
				File dest = new File(destDir, file.getName());
				if (file.isFile())
					copyFile(new FileInputStream(file), dest, overwrite);
				else
					copyDirectory(file, dest, overwrite);
			}

		}
	}

	public static void copyFile(File srcFile, File destFile) throws IOException {
		InputStream input = new FileInputStream(srcFile);
		copyFile(input, destFile);
	}

	public static void copyFile(InputStream srcStream, File destFile)
			throws IOException {
		copyFile(srcStream, destFile, false);
	}

	public static void copyFile(InputStream srcStream, File destFile,
			boolean overwrite) throws IOException {
		File parentFile = destFile.getParentFile();
		if (!parentFile.isDirectory())
			parentFile.mkdirs();
		if (destFile.exists()) {
			if (overwrite) {
				logger.debug("Overwriting file at: " + destFile.getAbsolutePath());
				writeStreamToFile(srcStream, destFile);
			} else {
				try {
					if (srcStream != null)
						srcStream.close();
				} catch (IOException e) {
				}
				logger.warn(destFile.getAbsolutePath() + " already exists");
			}
		} else {
			destFile.createNewFile();
			writeStreamToFile(srcStream, destFile);
		}
	}

	private static void writeStreamToFile(InputStream srcStream, File destFile)
			throws IOException {
		InputStream input;
		OutputStream output;
		input = null;
		output = null;
		try {
			input = new BufferedInputStream(srcStream);
			output = new BufferedOutputStream(new FileOutputStream(destFile));
			int ch;
			while ((ch = input.read()) != -1)
				output.write(ch);
		} catch (IOException e) {
			logger.error("Error writing stream to file: "
					+ destFile.getAbsolutePath());
			throw e;
		}
		try {
			input.close();
		} catch (IOException e) {
			throw e;
		}
		try {
			output.close();
		} catch (IOException e) {
			throw e;
		}
		try {
			input.close();
		} catch (IOException e) {
			throw e;
		}
		try {
			output.close();
		} catch (IOException e) {
			throw e;
		}

	}

	public static void saveTextFile(String stringContent, File destFile)
			throws IOException {
		ensureFileAndPathExist(destFile);
		FileWriter writer = new FileWriter(destFile);
		writer.write(stringContent);
		writer.close();
	}

	public static void ensureFileAndPathExist(File file) throws IOException {
		file.getParentFile().mkdirs();
		file.createNewFile();
	}

	public static List<String> readResourcesAsList(String resource) {
		List<String> result = new ArrayList();
		try {
			InputStream is = ClassLoaderUtils.getResourceAsStream(resource,
					FileUtils.class);
			BufferedReader in = new BufferedReader(new InputStreamReader(is));
			do {
				String s;
				if ((s = in.readLine()) == null)
					break;
				String niceS = StringUtils.trim(s);
				if (StringUtils.isNotBlank(niceS) && niceS.charAt(0) != '#')
					result.add(s);
			} while (true);
			is.close();
		} catch (IOException e) {
			logger.error("IOException reading stream: " + e, e);
		}
		return result;
	}

	public static String getResourceContent(String resource) {
		InputStream is = ClassLoaderUtils.getResourceAsStream(resource,
				FileUtils.class);
		return getInputStreamTextContent(is);
	}

	/*
	 * public static String getResourceContent(HttpServletRequest req, String
	 * resource) { InputStream is = req.getSession().getServletContext()
	 * .getResourceAsStream(resource); String result =
	 * getInputStreamTextContent(is); if (result == null) result = ""; return
	 * result; }
	 */

	public static String getInputStreamTextContent(InputStream is) {
		if (is == null)
			return null;
		String result = null;
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream(is
					.available());
			pump(is, baos);
			result = new String(baos.toByteArray());
			is.close();
		} catch (IOException e) {
			logger.error("IOException reading stream: " + e, e);
		}
		return result;
	}

	private static void pump(InputStream is, OutputStream os)
			throws IOException {
		byte buffer[] = new byte[1024];
		int lengthRead;
		while ((lengthRead = is.read(buffer)) >= 0) {
			os.write(buffer, 0, lengthRead);
		}
	}

	public static boolean deleteDir(File dir) {
		if (dir == null)
			return false;
		File candir;
		try {
			candir = dir.getCanonicalFile();
		} catch (IOException e) {
			return false;
		}
		if (!candir.equals(dir.getAbsoluteFile()))
			return false;
		File files[] = candir.listFiles();
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				File file = files[i];
				boolean deleted = !file.delete();
				if (deleted && file.isDirectory())
					deleteDir(file);
			}

		}
		return dir.delete();
	}

	public static boolean moveDir(File dirName, File destDir) {
		File destParent = new File(destDir.getParent());
		if (destDir.exists())
			destDir.delete();
		destParent.mkdirs();
		return dirName.renameTo(destDir);
	}

	public static void recursiveDelete(File file) {
		File files[] = null;
		if (file.isDirectory()) {
			files = file.listFiles();
		} else {
			file.delete();
			return;
		}
		for (int i = 0; i < files.length; i++) {
			File next = files[i];
			recursiveDelete(next);
		}

		file.delete();
	}

	public static void copyStream(InputStream in, OutputStream out)
			throws IOException {
		pump(in, out);
	}

}
